package com.example.JavaWebApi.service.impl.systemImpl;

import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.UpdateWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.example.JavaWebApi.core.apiinterceptors.Enum.RoleEnum;
import com.example.JavaWebApi.core.apiinterceptors.RequestHeaderContext;
import com.example.JavaWebApi.core.commonmodel.Exceptions.BusinessException;
import com.example.JavaWebApi.core.commonmodel.ResponseModel;
import com.example.JavaWebApi.core.commonmodel.ResponseTypeEnum;
import com.example.JavaWebApi.core.elasticsearch.ElasticSearchConfig;
import com.example.JavaWebApi.core.encryptionhelper.EncryptionHelper;
import com.example.JavaWebApi.core.jwthelper.JwtHelper;
import com.example.JavaWebApi.core.mybatisplusextention.wrapperCreator.QueryWrapperCreator;
import com.example.JavaWebApi.core.redis.RedisUtil;
import com.example.JavaWebApi.mapper.systemMapper.OrginfoMapper;
import com.example.JavaWebApi.mapper.systemMapper.UserinfoMapper;
import com.example.JavaWebApi.mapper.systemMapper.UsermaporgMapper;
import com.example.JavaWebApi.mapper.systemMapper.UsermaproleMapper;
import com.example.JavaWebApi.model.configmodel.TencentModel;
import com.example.JavaWebApi.model.entity.systemEntity.Orginfo;
import com.example.JavaWebApi.model.entity.systemEntity.Userinfo;
import com.example.JavaWebApi.model.entity.systemEntity.Usermaporg;
import com.example.JavaWebApi.model.entity.systemEntity.Usermaprole;
import com.example.JavaWebApi.model.querymodel.SystemQueryModel.AuthUserQuery;
import com.example.JavaWebApi.model.querymodel.SystemQueryModel.LoginData;
import com.example.JavaWebApi.model.querymodel.SystemQueryModel.UserInfoQuery;
import com.example.JavaWebApi.service.systemService.IFaceDetectionService;
import com.example.JavaWebApi.service.systemService.IUserinfoService;
import com.tencentcloudapi.iai.v20200303.models.SearchPersonsResponse;
import lombok.SneakyThrows;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * <p>
 *  服务实现类
 * </p>
 *
 * @author 杨泽
 * @since 2022-06-15
 */
@Service
public class UserinfoServiceImpl extends ServiceImpl<UserinfoMapper, Userinfo> implements IUserinfoService {
    @Autowired
    private EncryptionHelper encryptionHelper;
    @Autowired
    private UserinfoMapper userinfoMapper;
    @Autowired
    private OrginfoMapper orginfoMapper;
    @Autowired
    private UsermaporgMapper usermaporgMapper;
    @Autowired
    private UsermaproleMapper usermaproleMapper;
    @Autowired
    private UsermaporgServiceImpl usermaporgService;
    @Value("${adks.SuperAdminConfig.account}")
    private String SuperAdminAccount;
    @Value("${adks.SuperAdminConfig.password}")
    private String SuperAdminPassword;
    @Value("${ElasticSearch.CustomerIndex}")
    private String CustomerIndex;
    @Autowired
    private ElasticSearchConfig client;
    @Autowired
    private RedisUtil redisUtil;
    @Autowired
    private IFaceDetectionService faceDetectionService;
    @Autowired
    private TencentModel tencentModel;
    @SneakyThrows
    @Override
    public ResponseModel<String> login(LoginData loginData) {
        ResponseModel<String> result=new ResponseModel<>();
        Userinfo userinfo=new Userinfo();
        if (loginData.getAccount().equals(SuperAdminAccount)&&loginData.getPassword().equals(SuperAdminPassword)){
            userinfo.setId(-9999);
            userinfo.setUserName("超级管理员");
            userinfo.setUserRole(RoleEnum.SuperAdmin.toString());
        }
        else {
            String encryption=encryptionHelper.encrypt(loginData.getPassword());
            QueryWrapper<Userinfo> queryWrapper=new QueryWrapper<>();
            queryWrapper.eq("UserAccount",loginData.getAccount())
                    .eq("UserPassWord",encryption)
                    .eq("UserRole", RoleEnum.Admin.toString());
            userinfo=userinfoMapper.selectOne(queryWrapper);
            if (userinfo==null){
                throw new BusinessException(ResponseTypeEnum.FailLogin);
            }
            QueryWrapper<Orginfo> queryWrapper1=new QueryWrapper<>();
            queryWrapper1.apply("exists (select 1 from sys_usermaporg where UserId={0})",userinfo.getId());
            List<Orginfo> orginfoList=orginfoMapper.selectList(queryWrapper1);
            //userinfo.setUserPassWord(null);
            userinfo.setOrgInfoList(orginfoList);
            QueryWrapper<Usermaprole> queryWrapper2=new QueryWrapper<>();
            queryWrapper2.eq("userId",userinfo.getId());
            List<Usermaprole> usermaproleList=usermaproleMapper.selectList(queryWrapper2);
            userinfo.setRoleIdList(usermaproleList.stream().map(t->t.getRoleID()).collect(Collectors.toList()));
        }
        String userJson= JSONObject.toJSONString(userinfo);
        HashMap<String,String> payload=new HashMap<>();
        payload.put("userInfo",userJson);
        payload.put("role",userinfo.getUserRole());
        String token=JwtHelper.createToken(payload);
        result.setItems(token);
        result.setMessage("登录成功");
        result.setCode(2000);
        return result;
    }

    @Override
    public Page<Userinfo> getUserList(UserInfoQuery query) {
        QueryWrapperCreator<UserInfoQuery> creator = new QueryWrapperCreator<>(query);
        QueryWrapper<Userinfo> queryWrapper = creator.createWrapper();
        if(query.getRoleId()!=null && query.getIsAuth()!=null){
            String applySql="exists(select 1 from sys_usermaprole sub where sub.RoleId={0} and sub.UserId=a.Id)";
            if(!query.getIsAuth()){
                applySql="not "+applySql;
            }
            queryWrapper.apply(applySql,query.getRoleId());
        }
        IPage<Userinfo> page = new Page<>(query.getPage(), query.getLimit());
        Page<Userinfo> result = this.baseMapper.getUserList(page, queryWrapper);
        ;
        List<Integer> userIds = result.getRecords().stream().map(t -> t.getId()).collect(Collectors.toList());
        QueryWrapper<Usermaporg> queryWrapper1 = new QueryWrapper<>();
        queryWrapper1.in(userIds.size() > 0, "UserId", userIds);
        List<Usermaporg> usermaporgList = usermaporgMapper.selectList(queryWrapper1);
        List<Integer> orgIds = usermaporgList.stream().map(t -> t.getOrgID()).collect(Collectors.toList());
        QueryWrapper<Orginfo> queryWrapper2 = new QueryWrapper<>();
        queryWrapper2.in(orgIds.size() > 0, "Id", orgIds);
        List<Orginfo> orginfoList = orginfoMapper.selectList(queryWrapper2);
        result.getRecords().forEach(t->{
            List<Integer> userOrgIds=usermaporgList.stream().filter(a->a.getUserID().equals(t.getId())).map(a->a.getOrgID()).collect(Collectors.toList());
            List<Orginfo> userOrgList=orginfoList.stream().filter(a->userOrgIds.contains(a.getId())).collect(Collectors.toList());
            t.setOrgInfoList(userOrgList);
            t.setOrgIdList(userOrgIds);
            t.setUserPassWord(null);
        });
        return result;
    }


    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public Boolean create(Userinfo userinfo) {
        QueryWrapper<Userinfo> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("UserAccount",userinfo.getUserAccount());
        long count=this.baseMapper.selectCount(queryWrapper);
        if(count!=0){
            throw new BusinessException(ResponseTypeEnum.UserExist);
        }
        else {
            String pwd=encryptionHelper.encrypt(userinfo.getUserPassWord());
            userinfo.setUserPassWord(pwd);
            this.baseMapper.insert(userinfo);
            saveUserMapOrg(userinfo);
            return true;
        }
    }

    @SneakyThrows
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean update(Userinfo userinfo) {
        userinfo.setUserAccount(null);
        if (StringUtils.isNotBlank(userinfo.getUserPassWord())){
            String pwd=encryptionHelper.encrypt(userinfo.getUserPassWord());
            userinfo.setUserPassWord(pwd);
        }
        UpdateWrapper<Usermaporg> wrapper=new UpdateWrapper<>();
        wrapper.eq("UserId",userinfo.getId());
        usermaporgMapper.delete(wrapper);
        saveUserMapOrg(userinfo);
        return this.baseMapper.updateById(userinfo)>0;
    }
    private void saveUserMapOrg(Userinfo userinfo){
        if (userinfo.getOrgIdList()!=null){
            List<Usermaporg> list=new ArrayList<>();
            userinfo.getOrgIdList().forEach(t->{
                Usermaporg item=new Usermaporg();
                item.setUserID(userinfo.getId());
                item.setOrgID(t);
                list.add(item);
            });
            usermaporgService.saveBatch(list);
        }
    }
    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean delete(String Id) {
        UpdateWrapper<Usermaporg> wrapper=new UpdateWrapper<>();
        wrapper.eq("UserId",Id);
        usermaporgMapper.delete(wrapper);
        return this.baseMapper.deleteById(Id)>0;
    }

    @Override
    public IPage<Userinfo> getAuthorizationUserList(AuthUserQuery query) {
        Page<Userinfo> pageModel=new Page<>(query.getPage(),query.getLimit());
        QueryWrapper<Userinfo> queryWrapper=new QueryWrapper<>();
        String applySql="exists(select 1 from sys_usermaprole sub where sub.RoleId={0} and sub.UserId=a.Id)";
        if(!query.isAuth()){
            applySql="not "+applySql;
        }
        queryWrapper.apply(applySql,query.getRoleId());
        return this.baseMapper.getUserList(pageModel,queryWrapper);
    }

    @SneakyThrows
    @Override
    public Boolean updateUserPwd(String oldPwd, String newPwd) {
        Userinfo userinfo = RequestHeaderContext.getUserinfo();
        Integer userId=userinfo.getId();
        QueryWrapper<Userinfo> queryWrapper=new QueryWrapper<>();
        queryWrapper.eq("Id",userId)
                .eq("UserPassWord",encryptionHelper.encrypt(oldPwd));
        Userinfo database=this.baseMapper.selectOne(queryWrapper);
        if (database==null){
            throw new BusinessException(ResponseTypeEnum.Exception,"原密码错误！修改失败！");
        }
        else {
            UpdateWrapper<Userinfo> updateWrapper=new UpdateWrapper<>();
            updateWrapper.eq("Id",userId);
            updateWrapper.set("UserPassWord",encryptionHelper.encrypt(newPwd));
            return this.baseMapper.update(null,updateWrapper)>0;
        }
    }


    @Override
    public ResponseModel<String> updatePersonalInfo(Userinfo userinfo) {
        Userinfo tokenUser=RequestHeaderContext.getUserinfo();
        userinfo.setId(tokenUser.getId());
        this.baseMapper.updateById(userinfo);
        Userinfo user=this.baseMapper.selectById(userinfo.getId());
        LoginData loginData=new LoginData();
        loginData.setAccount(user.getUserAccount());
        loginData.setPassword(user.getUserPassWord());
        ResponseModel<String> result=login(loginData);
        result.setCode(2001);
        result.setMessage("操作成功");
        return result;
    }

    @Override
    public ResponseModel<String> faceLogin(String face) {
        ResponseModel<String> responseModel = new ResponseModel<>();
        SearchPersonsResponse response = faceDetectionService.searchPersonByPic(face);
        List<Integer> personIds = Arrays.stream(response.getResults())
                .flatMap(t -> Arrays.stream(t.getCandidates())
                        .filter(a -> a.getScore() >= tencentModel.getMinScore())
                        .map(a -> Integer.valueOf(a.getPersonId())))
                .distinct()
                .collect(Collectors.toList());
        if(personIds==null||personIds.size()==0){
            throw new BusinessException(ResponseTypeEnum.FailLogin);
        }
        else if(personIds.size()>1){
            responseModel.setCode(2002);
            responseModel.setMessage("识别到多个近似人员！！");
            responseModel.setItems(response.getRequestId());
            redisUtil.set(response.getRequestId(),personIds,5*60);
            return responseModel;
        }
        else {
            QueryWrapper<Userinfo> queryWrapper=new QueryWrapper<>();
            queryWrapper.lambda()
                    .in(Userinfo::getId,personIds);
            return userLogin(queryWrapper);
        }
    }

    @Override
    public ResponseModel<String> reCertification(String requestId,String message) {
        List<Integer> personIds=(List<Integer>)redisUtil.get(requestId);
        if(personIds==null){
            throw new BusinessException(ResponseTypeEnum.FailLogin);
        }
        redisUtil.del(requestId);
        QueryWrapper<Userinfo> queryWrapper=new QueryWrapper<>();
        queryWrapper.lambda()
                .in(Userinfo::getId,personIds)
                .likeRight(Userinfo::getUserPhone,message);
        return userLogin(queryWrapper);
    }
    private ResponseModel<String> userLogin(QueryWrapper<Userinfo> queryWrapper){
        Userinfo user=userinfoMapper.selectOne(queryWrapper);
        if(user==null){
            throw new BusinessException(ResponseTypeEnum.FailLogin);
        }
        else {
            LoginData data= new LoginData();
            data.setAccount(user.getUserAccount());
            data.setPassword(user.getUserPassWord());
            return login(data);
        }
    }

}
